package com.higgins.eventtracking.client.projectmanagement;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;

public class ProjectTable extends FlexTable	implements TreeListener, Refresher	{
	private final ProjectServiceAsync projectService = GWT
					.create(ProjectService.class);
	private Long parentId;
	private List<Refreshable> refreshables = new ArrayList<Refreshable>();
	private boolean refresh = false;
	
	public ProjectTable()	{
		super();
		initialise();
		addHandler();
	}
	public void addHandler()	{
		addClickHandler(new ClickHandler()	{

			@Override
			public void onClick(ClickEvent event) {
				Cell cell = getCellForEvent(event);
				final int row = cell.getRowIndex();
				final int column = cell.getCellIndex();
				if (row==0)
					addRow();
				else if (column==1 || column == 3 || column == 5 || column == 10)
					makeTableEditable(event);
				else if (column==2)
					moveUpPriority(event);
				else if (column==6)	
					startStopTimer(event);
			}
			
		});
	}
	public void moveUpPriority(ClickEvent event)	{
		Cell cell = getCellForEvent(event);
		final int row = cell.getRowIndex();
		final int column = cell.getCellIndex();
		Long id = getRowId(row);

		if (row > 1)	{
			Long cellAboveId = getRowId(row-1);
			projectService.updateProjectItemPriority(id, (row - 1), cellAboveId, (row), parentId, new AsyncCallback<List<Long>>()	{
				@Override
				public void onFailure(Throwable caught) {
				}
				@Override
				public void onSuccess(List<Long> result) {
					refresh = true;
					refresh();
//					int rowCount = getRowCount();
//					
//					CheckBox checkBox = (CheckBox)getWidget(rowCount - 1, 0);
//					if (checkBox.getName()==null)	{
//						checkBox.setName(result.toString());
//						System.out.println("Updated Checkbox Name");
//					}
				}
			});			
		}
		
	}
	public void startStopTimer(ClickEvent event)	{
		Cell cell = getCellForEvent(event);
		final int row = cell.getRowIndex();
		final int column = cell.getCellIndex();
		if (getText(row, column).equals("Start"))
			startTimer(row, column);
		else
			stopTimer(row, column);
	}
	private void startTimer(int row, int column)	{
		Long id = getRowId(row);
		projectService.startTimer(id, new AsyncCallback<Boolean>()	{
			@Override
			public void onFailure(Throwable caught) {
			}
			@Override
			public void onSuccess(Boolean result) {
			}
		});
		setText(row, column, "Stop");
	}
	private void stopTimer(int row, int column)	{
		Long id = getRowId(row);
		projectService.stopTimer(id, new AsyncCallback<Boolean>()	{
			@Override
			public void onFailure(Throwable caught) {
			}
			@Override
			public void onSuccess(Boolean result) {
				refresh = true;
				refresh();
			}
		});
		setText(row, column,"Start");
	}
	private void addRow(int rowCount, int column, String task, Double forecast, Double actual, Double complete, Boolean permanent, Boolean immediate, Boolean followUp, String followUpDate)	{
		addDeleteCheckBox(rowCount, column++, false, null);
		addString(rowCount, column++, task);
		addString(rowCount, column++, "Up");
		addDouble(rowCount, column++, forecast);
		addDouble(rowCount, column++, actual);
		addDouble(rowCount, column++, complete);
		addString(rowCount, column++, "Start");
		addPermanentCheckBox(rowCount, column++, permanent, null);
		addImmediateCheckBox(rowCount, column++, immediate, null);
		addFollowUpCheckBox(rowCount, column++, followUp, null);
		addString(rowCount, column++, followUpDate);
	}

	private void addRow()	{
		int rowCount = this.getRowCount();
		int column = 0;
		
		String task = "New Task";
		Double forecast = 0.0;
		Double actual = 0.0;
		Double complete = 0.0;
		Boolean permanent = false;
		Boolean immediate = false;
		Boolean followUp = false;
		String followUpDate = "";
		
		addRow(rowCount, column, task, forecast, actual, complete, permanent, immediate, followUp, followUpDate);
		insertNewTask(rowCount, column, task, forecast, actual, complete, permanent, immediate, followUp, followUpDate);

	}
	private Integer findRow(Long parentId)	{
		int rowCount = getRowCount();
		for (int count = 1; count < rowCount; count++)	{
			CheckBox checkBox = (CheckBox)getWidget(count, 0);
			if (checkBox.getName()!=null)	{
				if (parentId.equals(Long.parseLong(checkBox.getName())))
						return count;
			}
		}
		return null;
	}
	private void makeTableEditable(ClickEvent event)	{
		Cell cell = getCellForEvent(event);
		final int row = cell.getRowIndex();
		final int column = cell.getCellIndex();
		final TextBox textBox = new TextBox();
		textBox.setText(getText(row, column));
		textBox.addKeyDownHandler(new KeyDownHandler() {

			@Override
			public void onKeyDown(KeyDownEvent event) {
				// TODO Auto-generated method stub
				int code = event.getNativeKeyCode();
				if (KeyCodes.KEY_ENTER == code || KeyCodes.KEY_TAB == code)	{
					updateItemCell(row, column, textBox.getText());
					setWidget(row, column, new Label(textBox.getText()));
				}
				if (KeyCodes.KEY_ESCAPE == code)	{
					setWidget(row, column, new Label(textBox.getText()));
				}
			}
		});
		setWidget(row, column, textBox);
		textBox.setFocus(true);
		
	}
	private Long getRowId(int row)	{
		CheckBox checkBox = (CheckBox)getWidget(row, 0);
		String text = checkBox.getName();
		Long id = null;
		if (!text.equals("null"))
			id = Long.parseLong(text);
		else 
			refresh = true;
		return id;
	}
	private void updateRowWithId(Long id)		{
		int rowCount = getRowCount();
		
		CheckBox deletecheckBox = (CheckBox)getWidget(rowCount - 1, 0);
		CheckBox permanentCheckBox = (CheckBox)getWidget(rowCount - 1, 7);
		CheckBox immediateCheckBox = (CheckBox)getWidget(rowCount - 1, 8);
		CheckBox followUpCheckBox = (CheckBox)getWidget(rowCount - 1, 9);
		String name = deletecheckBox.getName();
		if (name==null || name.equals("null"))	{
			deletecheckBox.setName(id.toString());
			System.out.println("Updated Delete Checkbox Name");
		}
		name = permanentCheckBox.getName();
		if (name==null || name.equals("null"))	{
			permanentCheckBox.setName(id.toString());
			System.out.println("Updated Permanent Checkbox Name");
		}
		name = immediateCheckBox.getName();
		if (name==null || name.equals("null"))	{
			immediateCheckBox.setName(id.toString());
			System.out.println("Updated Immediate Checkbox Name");
		}	
		name = followUpCheckBox.getName();
		if (name==null || name.equals("null"))	{
			followUpCheckBox.setName(id.toString());
			System.out.println("Updated FollowUp Checkbox Name");
		}
		refresh = true;
		refresh();
	}
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void updateItemCell(int row, int column, String value)	{
		Long id = getRowId(row);
		switch (column)		{
		case 1:	
			projectService.updateProjectItemTask(id, value, parentId, new AsyncCallback<Long>()	{
				@Override
				public void onFailure(Throwable caught) {
				}
				@Override
				public void onSuccess(Long result) {
					updateRowWithId(result);
				}
			});
			break;

		case 3: 
			projectService.updateProjectItemForecast(id, Double.parseDouble(value), parentId, new AsyncCallback<Long>()	{
				@Override
				public void onFailure(Throwable caught) {
				}
				@Override
				public void onSuccess(Long result) {
					updateRowWithId(result);
				}
			});
			break;
		case 5: 
			projectService.updateProjectItemComplete(id, Double.parseDouble(value), parentId, new AsyncCallback<Long>()	{
				@Override
				public void onFailure(Throwable caught) {
				}
				@Override
				public void onSuccess(Long result) {
					refresh=true;
					updateRowWithId(result);		
				}
			});
			break;
		case 10: 
			projectService.updateFollowUpDate(id, value, new AsyncCallback<Long>()	{
				@Override
				public void onFailure(Throwable caught) {
				}
				@Override
				public void onSuccess(Long result) {
					refresh=true;
					updateRowWithId(result);		
				}
			});
			break;			
		}
	}

	private void insertNewTask(int rowCount, int column, String task, Double forecast, Double actual, Double complete, Boolean permanent, Boolean immediate, Boolean followUp, String followUpDate)	{
		Integer priority = rowCount;
		
		ProjectItemDTO item = new ProjectItemDTO();
		item.setTask(task);
		item.setForecast(forecast);
		item.setActual(actual);
		item.setComplete(complete);
		item.setPriority(priority);
		item.setParentId(parentId);
		item.setPermanent(permanent);
		item.setImmediate(immediate);
		item.setFollowUp(followUp);
		item.setFollowUpDateString(followUpDate);
		
		projectService.insetProjectItem(item, new AsyncCallback<Long>() {
			@Override
			public void onFailure(Throwable caught) {
			}
			@Override
			public void onSuccess(Long result) {
				updateRowWithId(result);
			}
		});		
	}

	
	public void initialise()	{
		this.setCellPadding(1);
		this.setCellSpacing(0);
//		this.setWidth("750px");
		this.setWidth("800px");

		
		getColumnFormatter().setWidth(0, "5%"); 
		getColumnFormatter().setWidth(1, "42%"); 
		getColumnFormatter().setWidth(2,"6%"); 
		getColumnFormatter().setWidth(3,"6%"); 
		getColumnFormatter().setWidth(4,"6%"); 
		getColumnFormatter().setWidth(5,"6%"); 
		getColumnFormatter().setWidth(6,"6%"); 
		getColumnFormatter().setWidth(7,"5%"); 
		getColumnFormatter().setWidth(8,"5%"); 
		getColumnFormatter().setWidth(9,"5%"); 
		getColumnFormatter().setWidth(10,"8%"); 
		
		addDeleteCheckBox(0,0, false, null);
		this.setText(0,1,"Task");
		this.setText(0,2,"Priority");
		this.setText(0,3,"Forecast");
		this.setText(0,4,"Actual");
		this.setText(0,5,"Complete");
		this.setText(0,6,"Timer");
		this.setText(0,7,"Perm");
		this.setText(0,8,"Imm");
		this.setText(0,9,"F-Up");
		this.setText(0,10,"F-Up Date");
		
		RowFormatter rf = this.getRowFormatter();
		rf.setStyleName(0, "FlexTable-HeaderRow");
		this.getCellFormatter().addStyleName(0, 0,"FlexTable-checkBoxCell");
		this.getCellFormatter().addStyleName(0, 1,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 2,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 3,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 4,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 5,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 6,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 7,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 8,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 9,"FlexTable-normCell");
		this.getCellFormatter().addStyleName(0, 10,"FlexTable-normCell");
	}	
	private void addDeleteCheckBox(int row, int column, Boolean apply, Long id)	{
		CheckBox checkBox = new CheckBox();
		checkBox.setName(id!=null?id.toString():"null");

		setWidget(row, column, checkBox);
		checkBox.setValue(apply!=null?apply:false);
		getCellFormatter().addStyleName(row, column, "FlexTable-checkBoxCell");
		addDeleteCheckBoxListener(checkBox);
	}
	private void addPermanentCheckBox(int row, int column, Boolean apply, Long id)	{
		CheckBox checkBox = new CheckBox();
		checkBox.setName(id!=null?id.toString():"null");

		setWidget(row, column, checkBox);
		checkBox.setValue(apply!=null?apply:false);
		getCellFormatter().addStyleName(row, column, "FlexTable-checkBoxCell");
		addPermanentCheckBoxListener(checkBox);
	}
	private void addImmediateCheckBox(int row, int column, Boolean apply, Long id)	{
		CheckBox checkBox = new CheckBox();
		checkBox.setName(id!=null?id.toString():"null");

		setWidget(row, column, checkBox);
		checkBox.setValue(apply!=null?apply:false);
		getCellFormatter().addStyleName(row, column, "FlexTable-checkBoxCell");
		addImmediateCheckBoxListener(checkBox);
	}	
	private void addFollowUpCheckBox(int row, int column, Boolean apply, Long id)	{
		CheckBox checkBox = new CheckBox();
		checkBox.setName(id!=null?id.toString():"null");

		setWidget(row, column, checkBox);
		checkBox.setValue(apply!=null?apply:false);
		getCellFormatter().addStyleName(row, column, "FlexTable-checkBoxCell");
		addFollowUpCheckBoxListener(checkBox);
	}	
	private void addDeleteCheckBoxListener(CheckBox checkBox)	{
		checkBox.addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				refresh = true;
				Cell cell = getCellForEvent(event);
				final int row = cell.getRowIndex();
				Object source = event.getSource();
				CheckBox chkBox = (CheckBox) source;
				String name = chkBox.getName();
				Long id = Long.parseLong(name);
				projectService.deleteProjectItem(id, new AsyncCallback<Boolean>(){
					@Override
					public void onFailure(Throwable caught) {
					}
					@Override
					public void onSuccess(Boolean result) {
						refresh();
					}
				});
				removeRow(row);
			}
			
		});
	}
	private void addPermanentCheckBoxListener(CheckBox checkBox)	{
		checkBox.addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				refresh = true;
				Cell cell = getCellForEvent(event);
				final int row = cell.getRowIndex();
				Object source = event.getSource();
				CheckBox chkBox = (CheckBox) source;
				String name = chkBox.getName();
				Long id = Long.parseLong(name);
				if (chkBox.getValue())	{
					projectService.setPermanent(id, new AsyncCallback<Boolean>(){
						@Override
						public void onFailure(Throwable caught) {
						}
						@Override
						public void onSuccess(Boolean result) {
						}
					});
				} else {
					projectService.setNotPermanent(id, new AsyncCallback<Boolean>(){
						@Override
						public void onFailure(Throwable caught) {
						}
						@Override
						public void onSuccess(Boolean result) {
						}
					});
				}
			}
		});
	}
	private void addImmediateCheckBoxListener(CheckBox checkBox)	{
		checkBox.addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				refresh = true;
				Cell cell = getCellForEvent(event);
				final int row = cell.getRowIndex();
				Object source = event.getSource();
				CheckBox chkBox = (CheckBox) source;
				String name = chkBox.getName();
				Long id = Long.parseLong(name);
				if (chkBox.getValue())	{
					projectService.setImmediate(id, new AsyncCallback<Boolean>(){
						@Override
						public void onFailure(Throwable caught) {
						}
						@Override
						public void onSuccess(Boolean result) {
						}
					});
				} else {
					projectService.setNotImmediate(id, new AsyncCallback<Boolean>(){
						@Override
						public void onFailure(Throwable caught) {
						}
						@Override
						public void onSuccess(Boolean result) {
						}
					});
				}
			}
		});
	}
	private void addFollowUpCheckBoxListener(CheckBox checkBox)	{
		checkBox.addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				refresh = true;
				Cell cell = getCellForEvent(event);
				final int row = cell.getRowIndex();
				Object source = event.getSource();
				CheckBox chkBox = (CheckBox) source;
				String name = chkBox.getName();
				Long id = Long.parseLong(name);
				if (chkBox.getValue())	{
					projectService.setFollowUp(id, new AsyncCallback<Boolean>(){
						@Override
						public void onFailure(Throwable caught) {
						}
						@Override
						public void onSuccess(Boolean result) {
						}
					});
				} else {
					projectService.setNotFollowUp(id, new AsyncCallback<Boolean>(){
						@Override
						public void onFailure(Throwable caught) {
						}
						@Override
						public void onSuccess(Boolean result) {
						}
					});
				}
			}
		});
	}	
	public void setProjectItems(List<ProjectItemDTO> projectItems)	{
		clearTable();
		int row = 1;
		for (ProjectItemDTO projectItem:projectItems)
			addRow(projectItem, row++);
	}
	private void clearTable()	{
		int rows = getRowCount();
		for (int row = 1; row < rows; row++)
			this.removeRow(getRowCount()-1);
	}
	public void addRow(ProjectItemDTO projectItem, int row)	{
		parentId = projectItem.getParentId();
		int column = 0;
		int rowCount = this.getRowCount();
		if (rowCount <= row)
			this.insertRow(rowCount);
		addDeleteCheckBox(row, column++, false, projectItem.getId());
		addString(row, column++, projectItem.getTask());
		addString(row, column++, "Up");
		addDouble(row, column++, projectItem.getForecast()!=null?projectItem.getForecast():0.0);
		addDouble(row, column++, projectItem.getActual()!=null?projectItem.getActual():0.0);
		addDouble(row, column++, projectItem.getComplete()!=null?projectItem.getComplete():0.0);
		addString(row, column++, "Start");
		addPermanentCheckBox(row, column++, projectItem.getPermanent(), projectItem.getId());
		addImmediateCheckBox(row, column++, projectItem.getImmediate(), projectItem.getId());
		addFollowUpCheckBox(row, column++, projectItem.getFollowUp(), projectItem.getId());
		addString(row, column++, projectItem.getFollowUpDateString());
		projectService.isActive(projectItem.getId(), new AsyncCallback<Long>()  {
			@Override
			public void onFailure(Throwable caught) {
				System.out.println("isActive Failed!! " + caught.toString());
			}
			@Override
			public void onSuccess(Long result) {
				if (result!=null)	{
					int row = findRow(result);
					addString(row, 6, "Stop");
				}
			}
		});
//		projectService.updateProjectItemPriority(projectItem.getId(), rowCount, projectItem.getParentId(), 
//				new AsyncCallback<Long>()	{
//					@Override
//					public void onFailure(Throwable caught) {
//					}
//					@Override
//					public void onSuccess(Long result) {
//					}
//		});
	}
	private void addString(int row, int column, String text)	{
		this.setText(row,column,text);
		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");
	}
	private void addDouble(int row, int column, Double number)	{
		this.setText(row, column,convertDoubleToString(number));
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");
	}
	public String convertDoubleToString(Double inValue){
		String stringValue = inValue.toString();
		int positionOfDot = stringValue.indexOf(".");
		int lengthOfNumberText = stringValue.length();
		if ((lengthOfNumberText - positionOfDot) > 4)
			lengthOfNumberText = positionOfDot+4;
		if (positionOfDot>0)
			stringValue = stringValue.substring(0, lengthOfNumberText);
		return stringValue;
	}	
	@Override
	public void update(List<ProjectItemDTO> projectItems) {
		setProjectItems(projectItems);
	}
	@Override
	public void setParentId(Long parentId) {
		this.parentId = parentId;
	}
	@Override
	public void addRefreshable(Refreshable refreshable) {
		refreshables.add(refreshable);
	}
	private void refresh()	{
		if (refresh)
			for (Refreshable refreshable:refreshables)
				refreshable.refreshSelectedOnly();
		refresh = false;
	}
}
